#ifndef _CTRIANGLE2D_H_
#define _CTRIANGLE2D_H_

#include "StdDefs.h"
#include "CMathFixed.h"
#include "CVector2d.h"
#include "CLineSegment2d.h"
#include "CSpace.h"
#include "CWinding.h"
#include "CCircle.h"

class CTriangle2d
{
public:
	CTriangle2d();
	CTriangle2d( const CVector2d& v0, const CVector2d& v1, const CVector2d& v2 );
	~CTriangle2d();

	// http://geometryalgorithms.com/Archive/algorithm_0101/algorithm_0101.htm

	// isLeft(): tests if a point is Left|On|Right of an infinite line.
	//    Input:  three points P0, P1, and P2
	//    Return: >0 for P2 left of the line through P0 and P1
	//            =0 for P2 on the line
	//            <0 for P2 right of the line

	// basically is the kth component cross products of the sides, which is useful for many calculations

	static fixed					IsLeft( const CVector2d& v0, const CVector2d& v1, const CVector2d& v2 );

	static boolean					Sweep( const CVector2d& t0v0, const CVector2d& t0v1, const CVector2d& t0v2, 
										   const CVector2d& t1v0, const CVector2d& t1v1, const CVector2d& t1v2,  
										   const CVector2d& v1, const CVector2d& v2, fixed &u ); // triangle - triangle sweep
	
	static boolean					Intersects( const CVector2d& t0v0, const CVector2d& t0v1, const CVector2d& t0v2,
												const CVector2d& t1v0, const CVector2d& t1v1, const CVector2d& t1v2 ); // triangle - triangle

	static boolean					Intersects( const CVector2d& tv0, const CVector2d& tv1, const CVector2d& tv2, 
												const CVector2d& v0, const CVector2d& v1, fixed& u, fixed& v ); // triangle - segment

	static CSpace::Relativity		DetermineSpace( const CVector2d& tv0, const CVector2d& tv1, const CVector2d& tv2, const CVector2d& pt );
	static CSpace::Relativity		DetermineSpace( const CVector2d& tv0, const CVector2d& tv1, const CVector2d& tv2, const CVector2d& v0, const CVector2d& v1 );

	static void						Barycentric( const CVector2d& tv0, const CVector2d& tv1, const CVector2d& tv2, const CVector2d& p, fixed &u, fixed &v, fixed &w );

	boolean							Sweep( const CTriangle2d& t2, const CVector2d& v1, const CVector2d& v2, fixed &u ) const;
	boolean							Intersects( const CTriangle2d& t ) const;
	boolean							Intersects( const CLineSegment2d& seg, fixed& u, fixed& v ) const;
	CSpace::Relativity				DetermineSpace( const CVector2d& pt ) const;
	CSpace::Relativity				DetermineSpace( const CLineSegment2d& seg ) const;
	void							Barycentric( const CVector2d& p, fixed &u, fixed &v, fixed &w ) const;
	boolean							IsIsoceles() const;
	boolean							IsEquilateral() const;
	
	fixed							GetArea() const;

	void							ComputeIncenter( CVector2d& outPoint ) const;
	void							ComputeIncircle( CCircle& outCircle ) const;

	void							ComputeCircumcenter( CVector2d& outPoint ) const;
	void							ComputerCircumcircle( CCircle& outCircle ) const;

	CWinding::WindingOrder			GetWinding() const;
		
	CVector2d						m_v0;
	CVector2d						m_v1;
	CVector2d						m_v2;
};

inline
fixed CTriangle2d::IsLeft( const CVector2d& v0, const CVector2d& v1, const CVector2d& v2 )
{
	return ( CMathFixed::Mul( ( v1.m_i - v0.m_i ), ( v2.m_j - v0.m_j ) ) - CMathFixed::Mul( ( v2.m_i - v0.m_i ), ( v1.m_j - v0.m_j ) ) );
}


inline
boolean CTriangle2d::Sweep( const CTriangle2d& t2, const CVector2d& v1, const CVector2d& v2, fixed& u ) const
{
	return Sweep( this->m_v0, this->m_v1, this->m_v2,t2.m_v0, t2.m_v1, t2.m_v2, v1, v2, u );
}

inline
boolean CTriangle2d::Intersects( const CTriangle2d& t ) const
{
	return Intersects( this->m_v0, this->m_v1, this->m_v2, t.m_v0, t.m_v1, t.m_v2 );
}

inline
boolean CTriangle2d::Intersects( const CLineSegment2d& seg, fixed& u, fixed& v ) const
{
	return Intersects( this->m_v0, this->m_v1, this->m_v2, seg.m_v0, seg.m_v1, u, v );
}


inline
CSpace::Relativity CTriangle2d::DetermineSpace( const CVector2d& pt ) const
{
	return DetermineSpace( this->m_v0, this->m_v1, this->m_v2, pt );
}

inline
CSpace::Relativity CTriangle2d::DetermineSpace( const CLineSegment2d& seg ) const
{
	return DetermineSpace( m_v0, m_v1, m_v2, seg.m_v0, seg.m_v1 );
}


inline
void CTriangle2d::Barycentric( const CVector2d& p, fixed &u, fixed &v, fixed &w ) const
{
	Barycentric( m_v0, m_v1, m_v2, p, u, v, w );
}


inline
fixed CTriangle2d::GetArea() const
{
	fixed val = IsLeft( m_v0, m_v1, m_v2 );
	return CMathFixed::Abs( CMathFixed::Mul( val, CMathFixed_FloatToFixed( 0.5f ) ) );
}


inline
CWinding::WindingOrder CTriangle2d::GetWinding() const
{
	fixed val = IsLeft( m_v0, m_v1, m_v2 );
	if ( val >= 0 ) return CWinding::CCW;
	else return CWinding::CW;
}


#endif //_CTRIANGLE2D_H_